package main

import (
	"net/http"

	"github.com/gin-gonic/gin"
	"github.com/gin-gonic/gin/binding"
)

// 模拟的数据
var secrets = gin.H{
	"weiyigeek": gin.H{"email": "master@weiyigeek.top", "blog": "weiyigeek.top"},
}

// 绑定 FORM / JSON / XML
type Login struct {
	User     string `form:"user" json:"user" xml:"user"  binding:"required"`
	Password string `form:"password" json:"password" xml:"password" binding:"required"`
	// Birthday time.Time `form:"birthday" json:"birthday" xml:"birthday" time_format:"2006-01-02" time_utc:"1"`

}

// 你可以使用显式绑定声明绑定 Uri：
// c.ShouldBindWith(&uri, binding.Uri)
// 使用 ShouldBindUri 函数绑定 Uri 路由参数
func bindUri(c *gin.Context) {
	// 自定义结构体进行数据绑定
	type Person struct {
		ID   string `uri:"uuid" binding:"required"`
		Name string `uri:"name" binding:"required"`
	}
	var person Person
	// 绑定路由参数
	if err := c.ShouldBindUri(&person); err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"msg": err.Error()})
		return
	}
	c.JSON(http.StatusOK, gin.H{"name": person.Name, "uuid": person.ID})
}

// 使用 ShouldBindQuery 函数只绑定 url 查询参数而忽略 post 数据
func bindQuery(c *gin.Context) {
	// GET请求：url 查询参数的结构体
	type BlogUrl struct {
		Name string `form:"name" binding:"required"`
		Blog string `form:"blog" binding:"required"`
	}
	var site BlogUrl
	// 绑定 URL 请求参数
	if c.ShouldBindQuery(&site) == nil {
		c.JSON(http.StatusOK, gin.H{"code": 200, "data": gin.H{"name": site.Name, "blog": site.Blog}})
	} else {
		c.JSON(http.StatusOK, gin.H{"code": 0, "message": "Query Param Error!"})
	}
}

// 使用 ShouldBindJSON 绑定 JSON 数据
func bindJson(c *gin.Context) {
	var json Login
	if err := c.ShouldBindJSON(&json); err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
		return
	}
	if json.User != "weiyigeek" || json.Password != "123456" {
		c.JSON(http.StatusUnauthorized, gin.H{"code": 0, "status": "unauthorized"})
		return
	}
	c.JSON(http.StatusOK, gin.H{"code": 200, "status": "you are logged in"})
}

// 使用 ShouldBindXML 绑定 xml 数据
func bindXml(c *gin.Context) {
	var xml Login
	if err := c.ShouldBindXML(&xml); err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
		return
	}
	if xml.User != "weiyigeek" || xml.Password != "123456" {
		c.JSON(http.StatusUnauthorized, gin.H{"code": 0, "status": "unauthorized"})
		return
	}
	c.JSON(http.StatusOK, gin.H{"code": 200, "status": "you are logged in"})
}

// 使用 ShouldBindForm 绑定 表单 数据
func bindForm(c *gin.Context) {
	var form Login
	if err := c.ShouldBindWith(&form, binding.Form); err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
		return
	}
	if form.User != "weiyigeek" || form.Password != "123456" {
		c.JSON(http.StatusUnauthorized, gin.H{"code": 0, "status": "unauthorized"})
		return
	}
	c.JSON(http.StatusOK, gin.H{"code": 200, "status": "you are logged in"})
}

// 绑定表单数据至自定义结构体
type StructA struct {
	Name string `form:"name" json:"name" xml:"name" text:"name"`
}
type StructB struct {
	// 方式1
	NestedStruct StructA
	// 方式2
	// NestedStructPointer *StructA
	// 方式3
	// NestedAnonyStruct struct {
	// 		FieldX string `form:"field_x"`
	// }
	Blog string `form:"blog" json:"blog" xml:"blog" text:"name"`
}

func bindCustom(c *gin.Context) {
	var person StructB
	if c.Bind(&person) == nil {
		c.JSON(http.StatusOK, gin.H{
			"person": person.NestedStruct,
			"blog":   person.Blog,
		})
	} else {
		c.JSON(http.StatusBadRequest, gin.H{
			"message": "BadRequest",
		})
	}
}

func main() {
	// Default返回一个Engine实例，该实例已连接Logger和Recovery中间件。
	r := gin.Default()

	// 简单的路由组: v1
	v1 := r.Group("/v1")
	{
		// 示例1.使用 ShouldBindUri 函数绑定 Uri 路由参数
		v1.GET("/person/:name/:uuid", bindUri)

		// 示例2.使用 ShouldBindQuery 函数只绑定 url 查询参数而忽略 post 数据
		v1.Any("/site", bindQuery)
	}

	// 简单的路由组: v2
	v2 := r.Group("/v2")
	{
		// 示例3.使用 ShouldBindJSON 绑定 JSON 数据
		v2.POST("/loginJSON", bindJson)

		// 示例4.使用 ShouldBindXML 绑定 xml 数据
		v2.POST("/loginXML", bindXml)

		// 示例5.使用 ShouldBindForm 绑定 表单 数据
		v2.POST("/loginFORM", bindForm)
	}

	// 简单的路由组: v3
	v3 := r.Group("/v3")
	{
		v3.POST("/person", bindCustom)
	}

	// Listen and Server in 0.0.0.0:8080
	r.Run(":8080")
}
